package com.stars.pao.junit01;

import org.junit.jupiter.api.Test;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class PhoneBillCalculatorTest {

    @Test
    public void testCallDurationLessThan20Minutes() {
        PhoneBillCalculator calculator = new PhoneBillCalculator();
        LocalDateTime startTime = LocalDateTime.of(2024, 3, 10, 10, 0);
        LocalDateTime endTime = LocalDateTime.of(2024, 3, 10, 10, 15);
        double expected = 15 * 0.05;
        double actual = calculator.calculateBill(startTime, endTime);
        System.out.println("测试用例: 通话时长小于 20 分钟");
        System.out.println("预测结果: " + expected);
        System.out.println("实际结果: " + actual);
        assertEquals(expected, actual, 0.001);
    }

    @Test
    public void testCallDurationEqualTo20Minutes() {
        PhoneBillCalculator calculator = new PhoneBillCalculator();
        LocalDateTime startTime = LocalDateTime.of(2024, 3, 10, 10, 0);
        LocalDateTime endTime = LocalDateTime.of(2024, 3, 10, 10, 20);
        double expected = 20 * 0.05;
        double actual = calculator.calculateBill(startTime, endTime);
        System.out.println("测试用例: 通话时长等于 20 分钟");
        System.out.println("预测结果: " + expected);
        System.out.println("实际结果: " + actual);
        assertEquals(expected, actual, 0.001);
    }

    @Test
    public void testCallDurationGreaterThan20Minutes() {
        PhoneBillCalculator calculator = new PhoneBillCalculator();
        LocalDateTime startTime = LocalDateTime.of(2024, 3, 10, 10, 0);
        LocalDateTime endTime = LocalDateTime.of(2024, 3, 10, 10, 30);
        double expected = 1.00 + (30 - 20) * 0.10;
        double actual = calculator.calculateBill(startTime, endTime);
        System.out.println("测试用例: 通话时长大于 20 分钟");
        System.out.println("预测结果: " + expected);
        System.out.println("实际结果: " + actual);
        assertEquals(expected, actual, 0.001);
    }
    @Test
    public void testCallDurationWithSecondsRounding() {
        PhoneBillCalculator calculator = new PhoneBillCalculator();
        LocalDateTime startTime = LocalDateTime.of(2024, 3, 10, 10, 0);
        LocalDateTime endTime = LocalDateTime.of(2024, 3, 10, 10, 1, 30);
        double expected = 2 * 0.05;
        double actual = calculator.calculateBill(startTime, endTime);
        System.out.println("测试用例: 通话时长包含秒数需向上进位");
        System.out.println("预测结果: " + expected);
        System.out.println("实际结果: " + actual);
        assertEquals(expected, actual, 0.001);
    }


    @Test
    public void testSpringDaylightSavingTransition() {
        // 春季夏令时转换（2024 年 3 月 10 日凌晨 2:00 到 3:00）
        PhoneBillCalculator calculator = new PhoneBillCalculator();
        LocalDateTime startTime = LocalDateTime.of(2024, 3, 10, 1, 30);
        LocalDateTime endTime = LocalDateTime.of(2024, 3, 10, 3, 30);
        ZonedDateTime startZoned = ZonedDateTime.of(startTime, ZoneId.of("America/New_York"));
        ZonedDateTime endZoned = ZonedDateTime.of(endTime, ZoneId.of("America/New_York"));
        Duration duration = Duration.between(startZoned, endZoned);
        long minutes = (long) Math.ceil(duration.getSeconds() / 60.0);
        double expected;
        if (minutes <= 20) {
            expected = minutes * 0.05;
        } else {
            expected = 1.00 + (minutes - 20) * 0.10;
        }
        double actual = calculator.calculateBill(startTime, endTime);
        System.out.println("测试用例: 春季夏令时转换期间通话");
        System.out.println("预测结果: " + expected);
        System.out.println("实际结果: " + actual);
        assertEquals(expected, actual, 0.001);
    }

    // 测试夏令时转换
    @Test
    public void testAutumnDaylightSavingTransition() {
        // 秋季夏令时转换（2024 年 11 月 3 日凌晨 2:00 调回 2:00）
        PhoneBillCalculator calculator = new PhoneBillCalculator();
        LocalDateTime startTime = LocalDateTime.of(2024, 11, 3, 1, 30);
        LocalDateTime endTime = LocalDateTime.of(2024, 11, 3, 3, 30);
        ZonedDateTime startZoned = ZonedDateTime.of(startTime, ZoneId.of("America/New_York"));
        ZonedDateTime endZoned = ZonedDateTime.of(endTime, ZoneId.of("America/New_York"));
        Duration duration = Duration.between(startZoned, endZoned);
        long minutes = (long) Math.ceil(duration.getSeconds() / 60.0);
        double expected;
        if (minutes <= 20) {
            expected = minutes * 0.05;
        } else {
            expected = 1.00 + (minutes - 20) * 0.10;
        }
        double actual = calculator.calculateBill(startTime, endTime);
        System.out.println("测试用例: 秋季夏令时转换期间通话");
        System.out.println("预测结果: " + expected);
        System.out.println("实际结果: " + actual);
        assertEquals(expected, actual, 0.001);
    }
}